#
# OIDTree
# Copyright (C) 2010 Open Sistemas <imasd@opensistemas.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
package OpenSistemas::OID::Tree;

use strict;
use warnings;

use Carp;

use NetSNMP::OID;

my @TREE = ();
my %WRITABLE;
my %DIRECT;
my $SORTED = 0;

sub new
{
	my ($pkg) = @_;

  my $self = { };

	bless $self, $pkg;

	return $self;
}

sub sort
{
  return if $SORTED == 1;

  my @k = sort { $a cmp $b } keys(%DIRECT);

  my $i = 0;
  my @newt = ();
  foreach (@k)
  {
    $newt[$i] = $TREE[$DIRECT{$_}];
    $DIRECT{$_} = $i++;
  }
  @TREE = @newt;
  $SORTED = 1;
}

sub sorted
{
  return $SORTED == 1;
}

sub getnext
{
  my ($self, $oid) = @_;

  $self->sort() unless $SORTED == 1;

  $oid = $self->comparable_string($oid);

  if(exists $DIRECT{$oid} && $DIRECT{$oid}+1 < @TREE)
  {
    return $TREE[$DIRECT{$oid}+1];
  }
  else
  {
    return undef if exists $DIRECT{$oid} && $DIRECT{$oid}+1 >= @TREE;
    foreach (@TREE)
    {
      my $cmp = $self->comparable_string($_->{oid});
      next if length($cmp) < length($oid);
      return $_ if $oid eq substr($cmp, 0, length($oid));
    }
  }

  return undef;
}

sub get
{
  my ($self, $oid) = @_;

  $oid = $self->comparable_string($oid);
  return $TREE[$DIRECT{$oid}] if exists $DIRECT{$oid};

  return undef;
}

sub set
{
  my ($self, $item) = @_;
  my $idx = @TREE;

  croak 'OIDTree: no item to store' if !$item;

  my $oid = $item->{oid};
  $oid = $self->comparable_string($oid);

  # update
  if(exists $DIRECT{$oid})
  {
    $TREE[$DIRECT{$oid}] = $item;
  }
  else # new one
  {
    $TREE[$idx] = $item;
    $DIRECT{$oid} = $idx;
    $SORTED = 0;
  }
}

sub writable
{
  my ($self, $oid, $value) = @_;

  croak 'OIDTree: writable, OID missing' if !defined $oid;

  $oid = $self->comparable_string($oid);

  if($value)
  {
    my $old = $WRITABLE{$oid} ? $WRITABLE{$oid} : 0;
    $WRITABLE{$oid} = $value;
    return $old;
  }
  else
  {
    return $WRITABLE{$oid} if exists $WRITABLE{$oid};
  }

  return undef;
}

sub comparable_string
{
  my ($self, $oid) = @_;

  $oid = NetSNMP::OID->new($oid);

  my @arr = $oid->to_array();
  my $str;

  foreach(@arr)
  {
    $str = $str .sprintf('%08i', $_);
  }

  return $str;
}

1;
